package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.common.exception.Assert;
import com.atguigu.srb.common.exception.BusinessException;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.FormHelper;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.InvestVO;
import com.atguigu.srb.core.service.LendItemReturnService;
import com.atguigu.srb.core.service.LendItemService;
import com.atguigu.srb.core.service.LendService;
import com.atguigu.srb.core.util.LendNoUtils;
import com.atguigu.srb.core.util.LendUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 标的出借记录表 服务实现类
 * </p>
 *
 * @author lsyandwh
 * @since 2022-12-02
 */
@Service
@Transactional
public class LendItemServiceImpl extends ServiceImpl<LendItemMapper, LendItem> implements LendItemService {

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private LendMapper lendMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private LendService lendService;

    @Autowired
    private TransFlowMapper transFlowMapper;

    @Override
    public String commitInvest(InvestVO investVO, String userId) {

        //1.判断当前标的状态
        //获取标的信息
        Lend lend = lendMapper.selectById(investVO.getLendId());
        Assert.equals(lend.getStatus(),LendStatusEnum.INVEST_RUN.getStatus(),ResponseEnum.LEND_FULL_SCALE_ERROR);

        //2.判断投标金额是否超出标的金额
        //获取已投金额
        BigDecimal investAmount = lend.getInvestAmount();
        //投标总金额
        BigDecimal add = investAmount.add(new BigDecimal(investVO.getInvestAmount()));
        //投标总金额 > 借款金额 抛出异常
        if(add.compareTo(lend.getAmount()) == 1){
            throw new BusinessException(ResponseEnum.EXCEED_FUNDS_ERROR);
        }

        //3.判断用户余额是否足够
        QueryWrapper<UserAccount> userAccountWrapper = new QueryWrapper<>();
        userAccountWrapper.eq("user_id",userId);
        UserAccount userAccount = userAccountMapper.selectOne(userAccountWrapper);
        //投资人余额
        BigDecimal amount = userAccount.getAmount();
        //投资金额
        BigDecimal thisInvestAmount = new BigDecimal(investVO.getInvestAmount());
        //投资人余额 < 投资金额 抛出异常
        if(amount.compareTo(thisInvestAmount) == -1){
            throw new BusinessException(ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);
        }

        //4.生成投资信息
        UserInfo userInfo = userInfoMapper.selectById(Long.parseLong(userId));
        LendItem lendItem = new LendItem();
        String lendItemNo = LendNoUtils.getLendItemNo();
        lendItem.setLendId(lend.getId());//标的id
        lendItem.setLendItemNo(lendItemNo);//投资单号
        lendItem.setInvestUserId(Long.parseLong(userId));//投资人id
        lendItem.setInvestName(userInfo.getName());//投资人姓名
        lendItem.setInvestAmount(new BigDecimal(investVO.getInvestAmount()));//投资金额
        lendItem.setLendYearRate(lend.getLendYearRate());//标的利率
        lendItem.setInvestTime(LocalDateTime.now());
        lendItem.setLendStartDate(lend.getLendStartDate());
        lendItem.setLendEndDate(lend.getLendEndDate());
        //预计收益 投资金额 投资利率 投资时间 还款方式
        BigDecimal interestCount = lendService.getInterestCount(lendItem.getInvestAmount(), lendItem.getLendYearRate(), lend.getPeriod(), lend.getReturnMethod());
        lendItem.setExpectAmount(interestCount);//预计收益
        lendItem.setRealAmount(new BigDecimal("0"));//实际收益
        lendItem.setStatus(0);
        baseMapper.insert(lendItem);

        //5.生成表单页面
        //获取投资人绑定code
        String itemBindCode = userInfo.getBindCode();
        //获取借款人绑定code
        UserInfo borrowUserInfo = userInfoMapper.selectById(lend.getUserId());
        String borrowBindCode = borrowUserInfo.getBindCode();
        //封装提交至汇付宝的参数
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("voteBindCode", itemBindCode);
        paramMap.put("benefitBindCode",borrowBindCode);
        paramMap.put("agentProjectCode", lend.getLendNo());//项目标号
        paramMap.put("agentProjectName", lend.getTitle());

        //在资金托管平台上的投资订单的唯一编号，要和lendItemNo保持一致。
        paramMap.put("agentBillNo", lendItemNo);//订单编号
        paramMap.put("voteAmt", investVO.getInvestAmount());
        paramMap.put("votePrizeAmt", "0");
        paramMap.put("voteFeeAmt", "0");
        paramMap.put("projectAmt", lend.getAmount()); //标的总金额
        paramMap.put("note", "");
        paramMap.put("notifyUrl", HfbConst.INVEST_NOTIFY_URL); //检查常量是否正确
        paramMap.put("returnUrl", HfbConst.INVEST_RETURN_URL);
        paramMap.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(paramMap);
        paramMap.put("sign", sign);

        //构建充值自动提交表单
        String formStr = FormHelper.buildForm(HfbConst.INVEST_URL, paramMap);

        return formStr;
    }

    @Override
    public void lendItemNotify(Map<String, Object> paramMap) {

        //1.校验幂等性
        //获取投资编号
        String agentBillNo = (String) paramMap.get("agentBillNo");

        QueryWrapper<TransFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("trans_no",agentBillNo);
        TransFlow transFlow = transFlowMapper.selectOne(wrapper);

        if(transFlow == null){
            //投资金额
            String voteAmt = (String)paramMap.get("voteAmt");
            //投资人绑定code
            String bindCode = (String)paramMap.get("voteBindCode");

            //获取投资人信息
            QueryWrapper<UserInfo> userInfoWrapper = new QueryWrapper<>();
            userInfoWrapper.eq("bind_code",bindCode);
            UserInfo userInfo = userInfoMapper.selectOne(userInfoWrapper);

            //2.修改用户资金
            QueryWrapper<UserAccount> userAccountWrapper = new QueryWrapper<>();
            userAccountWrapper.eq("user_id",userInfo.getId());
            UserAccount userAccount = userAccountMapper.selectOne(userAccountWrapper);
            //剩余资金 = 原始资金 - 投资资金
            userAccount.setAmount(userAccount.getAmount().subtract(new BigDecimal(voteAmt)));
            //设置冻结资金
            userAccount.setFreezeAmount(userAccount.getFreezeAmount().add(new BigDecimal(voteAmt)));
            userAccountMapper.updateById(userAccount);

            //3.设置lent_item表的状态
            QueryWrapper<LendItem> lendItemWrapper = new QueryWrapper<>();
            lendItemWrapper.eq("lend_item_no",agentBillNo);
            LendItem lendItem = baseMapper.selectOne(lendItemWrapper);
            lendItem.setStatus(1);//设置当前投标状态为已支付
            baseMapper.updateById(lendItem);

            //4.修改标的信息
            Lend lend = lendMapper.selectById(lendItem.getLendId());
            lend.setInvestAmount(lend.getInvestAmount().add(new BigDecimal(voteAmt)));//已投金额
            lend.setInvestNum(lend.getInvestNum() + 1);
            lendMapper.updateById(lend);

            //5.生成流水订单
            transFlow = new TransFlow();
            transFlow.setTransNo(agentBillNo);//流水单号
            transFlow.setMemo("投标流水");
            transFlow.setUserId(userInfo.getId());//投资人id
            transFlow.setUserName(userInfo.getName());//投资人姓名
            transFlow.setTransType(TransTypeEnum.INVEST_LOCK.getTransType());//交易类型
            transFlow.setTransTypeName(TransTypeEnum.INVEST_LOCK.getTransTypeName());
            transFlow.setTransAmount(new BigDecimal(voteAmt));//投资金额
            transFlowMapper.insert(transFlow);
        }
    }
}
